#include "basechart_layoutitem.h"

#include "basechart_plot.h"

////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////// BaseChartTextElement
////////////////////////////////////////////////////////////////////////////////////////////////////

/*! \class BaseChartTextElement
  \brief A layout element displaying a text

  The text may be specified with \ref setText, the formatting can be controlled
  with \ref setFont, \ref setTextColor, and \ref setTextFlags.

  A text element can be added as follows:
  \snippet documentation/doc-code-snippets/mainwindow.cpp
  qcptextelement-creation
*/

/* start documentation of signals */

/*! \fn void BaseChartTextElement::selectionChanged(bool selected)

  This signal is emitted when the selection state has changed to \a selected,
  either by user interaction or by a direct call to \ref setSelected.

  \see setSelected, setSelectable
*/

/*! \fn void BaseChartTextElement::clicked(QMouseEvent *event)

  This signal is emitted when the text element is clicked.

  \see doubleClicked, selectTest
*/

/*! \fn void BaseChartTextElement::doubleClicked(QMouseEvent *event)

  This signal is emitted when the text element is double clicked.

  \see clicked, selectTest
*/

/* end documentation of signals */

/*! \overload

  Creates a new BaseChartTextElement instance and sets default values. The
  initial text is empty (\ref setText).
*/
BaseChartTextElement::BaseChartTextElement(BaseChartCustomPlot* parentPlot)
    : BaseChartLayoutElement(parentPlot),
      mTextFlags(Qt::AlignCenter),
      mOffset(0),
      mFont(
          QFont(QLatin1String("sans serif"),
                12)),  // will be taken from parentPlot if available, see below
      mTextColor(Qt::gray),
      mSelectedFont(
          QFont(QLatin1String("sans serif"),
                12)),  // will be taken from parentPlot if available, see below
      mSelectedTextColor(Qt::blue),
      mSelectable(false),
      mSelected(false),
      mCustomTextElement(nullptr) {
  if (parentPlot) {
    mFont = parentPlot->font();
    mSelectedFont = parentPlot->font();
  }
  setMargins(QMargins(2, 2, 2, 2));
}

/*! \overload

  Creates a new BaseChartTextElement instance and sets default values.

  The initial text is set to \a text.
*/
BaseChartTextElement::BaseChartTextElement(BaseChartCustomPlot* parentPlot,
                                           const QString& text)
    : BaseChartLayoutElement(parentPlot),
      mTextFlags(Qt::AlignCenter),
      mOffset(0),
      mFont(
          QFont(QLatin1String("sans serif"),
                12)),  // will be taken from parentPlot if available, see below
      mTextColor(Qt::gray),
      mSelectedFont(
          QFont(QLatin1String("sans serif"),
                12)),  // will be taken from parentPlot if available, see below
      mSelectedTextColor(Qt::blue),
      mSelectable(false),
      mSelected(false),
      mCustomTextElement(nullptr) {
  mText[0] = text;
  if (parentPlot) {
    mFont = parentPlot->font();
    mSelectedFont = parentPlot->font();
  }
  setMargins(QMargins(2, 2, 2, 2));
}

/*! \overload

  Creates a new BaseChartTextElement instance and sets default values.

  The initial text is set to \a text with \a pointSize.
*/
BaseChartTextElement::BaseChartTextElement(BaseChartCustomPlot* parentPlot,
                                           const QString& text,
                                           double pointSize)
    : BaseChartLayoutElement(parentPlot),
      mTextFlags(Qt::AlignCenter),
      mOffset(0),
      mFont(QFont(QLatin1String("sans serif"),
                  int(pointSize))),  // will be taken from parentPlot if
                                     // available, see below
      mTextColor(Qt::gray),
      mSelectedFont(QFont(QLatin1String("sans serif"),
                          int(pointSize))),  // will be taken from parentPlot if
                                             // available, see below
      mSelectedTextColor(Qt::blue),
      mSelectable(false),
      mSelected(false),
      mCustomTextElement(nullptr) {
  mText[0] = text;
  mFont.setPointSizeF(pointSize);  // set here again as floating point, because
                                   // constructor above only takes integer
  if (parentPlot) {
    mFont = parentPlot->font();
    mFont.setPointSizeF(pointSize);
    mSelectedFont = parentPlot->font();
    mSelectedFont.setPointSizeF(pointSize);
  }
  setMargins(QMargins(2, 2, 2, 2));
}

/*! \overload

  Creates a new BaseChartTextElement instance and sets default values.

  The initial text is set to \a text with \a pointSize and the specified \a
  fontFamily.
*/
BaseChartTextElement::BaseChartTextElement(BaseChartCustomPlot* parentPlot,
                                           const QString& text,
                                           const QString& fontFamily,
                                           double pointSize)
    : BaseChartLayoutElement(parentPlot),
      mTextFlags(Qt::AlignCenter),
      mOffset(0),
      mFont(QFont(fontFamily, int(pointSize))),
      mTextColor(Qt::gray),
      mSelectedFont(QFont(fontFamily, int(pointSize))),
      mSelectedTextColor(Qt::blue),
      mSelectable(false),
      mSelected(false),
      mCustomTextElement(nullptr) {
  mText[0] = text;
  mFont.setPointSizeF(pointSize);  // set here again as floating point, because
                                   // constructor above only takes integer
  setMargins(QMargins(2, 2, 2, 2));
}

/*! \overload

  Creates a new BaseChartTextElement instance and sets default values.

  The initial text is set to \a text with the specified \a font.
*/
BaseChartTextElement::BaseChartTextElement(BaseChartCustomPlot* parentPlot,
                                           const QString& text,
                                           const QFont& font)
    : BaseChartLayoutElement(parentPlot),
      mTextFlags(Qt::AlignCenter),
      mOffset(0),
      mFont(font),
      mTextColor(Qt::gray),
      mSelectedFont(font),
      mSelectedTextColor(Qt::blue),
      mSelectable(false),
      mSelected(false),
      mCustomTextElement(nullptr) {
  mText[0] = text;
  setMargins(QMargins(2, 2, 2, 2));
}

BaseChartTextElement::BaseChartTextElement(BaseChartCustomPlot* parentPlot,
                                           const QString& text1,
                                           const QString& text2,
                                           const QFont& font)
    : BaseChartLayoutElement(parentPlot),
      mTextFlags(Qt::AlignCenter),
      mOffset(0),
      mFont(font),
      mTextColor(Qt::gray),
      mSelectedFont(font),
      mSelectedTextColor(Qt::blue),
      mSelectable(false),
      mSelected(false),
      mCustomTextElement(nullptr) {
  mText[0] = text1;
  mText[1] = text2;
  setMargins(QMargins(2, 2, 2, 2));
}

/*!
  Sets the text that will be displayed to \a text. Multiple lines can be created
  by insertion of "\n".

  \see setFont, setTextColor, setTextFlags
*/
void BaseChartTextElement::setText(const QString& text, const QString& text2,
                                   const QString& text3, const QString& text4,
                                   const QString& text5, const QString& text6) {
  mText[0] = text;
  mText[1] = text2;
  mText[2] = text3;
  mText[3] = text4;
  mText[4] = text5;
  mText[5] = text6;
}

/*!
  Sets options for text alignment and wrapping behaviour. \a flags is a bitwise
  OR-combination of \c Qt::AlignmentFlag and \c Qt::TextFlag enums.

  Possible enums are:
  - Qt::AlignLeft
  - Qt::AlignRight
  - Qt::AlignHCenter
  - Qt::AlignJustify
  - Qt::AlignTop
  - Qt::AlignBottom
  - Qt::AlignVCenter
  - Qt::AlignCenter
  - Qt::TextDontClip
  - Qt::TextSingleLine
  - Qt::TextExpandTabs
  - Qt::TextShowMnemonic
  - Qt::TextWordWrap
  - Qt::TextIncludeTrailingSpaces
*/
void BaseChartTextElement::setTextFlags(int flags) { mTextFlags = flags; }

/*!
  Sets the \a font of the text.

  \see setTextColor, setSelectedFont
*/
void BaseChartTextElement::setFont(const QFont& font) { mFont = font; }

/*!
  Sets the \a color of the text.

  \see setFont, setSelectedTextColor
*/
void BaseChartTextElement::setTextColor(const QColor& color) {
  mTextColor = color;
}

/*!
  Sets the \a font of the text that will be used if the text element is selected
  (\ref setSelected).

  \see setFont
*/
void BaseChartTextElement::setSelectedFont(const QFont& font) {
  mSelectedFont = font;
}

/*!
  Sets the \a color of the text that will be used if the text element is
  selected (\ref setSelected).

  \see setTextColor
*/
void BaseChartTextElement::setSelectedTextColor(const QColor& color) {
  mSelectedTextColor = color;
}

/*!
  Sets whether the user may select this text element.

  Note that even when \a selectable is set to <tt>false</tt>, the selection
  state may be changed programmatically via \ref setSelected.
*/
void BaseChartTextElement::setSelectable(bool selectable) {
  if (mSelectable != selectable) {
    mSelectable = selectable;
    emit selectableChanged(mSelectable);
  }
}

/*!
  Sets the selection state of this text element to \a selected. If the selection
  has changed, \ref selectionChanged is emitted.

  Note that this function can change the selection state independently of the
  current \ref setSelectable state.
*/
void BaseChartTextElement::setSelected(bool selected) {
  if (mSelected != selected) {
    mSelected = selected;
    emit selectionChanged(mSelected);
  }
}

/* inherits documentation from base class */
void BaseChartTextElement::applyDefaultAntialiasingHint(
    BaseChartPainter* painter) const {
  applyAntialiasingHint(painter, mAntialiased, aeOther);
}

/* inherits documentation from base class */
void BaseChartTextElement::draw(BaseChartPainter* painter) {
  if (mCustomTextElement) {
    mCustomTextElement->customDraw(painter, mRect);
  }

  painter->setFont(mainFont());
  painter->setPen(QPen(mainTextColor()));

  QRect rcText = mRect;

  if (mText[5].length() > 0) {
    for (int i = 0; i < 6; i++) {
      rcText.setLeft(mRect.left() + mRect.width() / 6 * i + mOffset);
      painter->drawText(rcText, mTextFlags, mText[i], &mTextBoundingRect);
    }
  } else if (mText[4].length() > 0) {
    for (int i = 0; i < 5; i++) {
      rcText.setLeft(mRect.left() + mRect.width() / 5 * i + mOffset);
      painter->drawText(rcText, mTextFlags, mText[i], &mTextBoundingRect);
    }
  } else if (mText[3].length() > 0) {
    for (int i = 0; i < 4; i++) {
      rcText.setLeft(mRect.left() + mRect.width() / 4 * i + mOffset);
      painter->drawText(rcText, mTextFlags, mText[i], &mTextBoundingRect);
    }
  } else if (mText[2].length() > 0) {
    for (int i = 0; i < 3; i++) {
      rcText.setLeft(mRect.left() + mRect.width() / 3 * i + mOffset);
      painter->drawText(rcText, mTextFlags, mText[i], &mTextBoundingRect);
    }
  } else if (mText[1].length() > 0) {
    for (int i = 0; i < 2; i++) {
      rcText.setLeft(mRect.left() + mRect.width() / 2 * i + mOffset);
      painter->drawText(rcText, mTextFlags, mText[i], &mTextBoundingRect);
    }
  } else if (mText[0].length() > 0) {
    rcText.setLeft(rcText.left() + mOffset);
    painter->drawText(rcText, mTextFlags, mText[0], &mTextBoundingRect);
  }
}

/* inherits documentation from base class */
QSize BaseChartTextElement::minimumOuterSizeHint() const {
  QFontMetrics metrics(mFont);
  QSize result(
      metrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip, mText[0]).size());
  result.rwidth() += mMargins.left() + mMargins.right();
  result.rheight() += mMargins.top() + mMargins.bottom() + 8;
  return result;
}

/* inherits documentation from base class */
QSize BaseChartTextElement::maximumOuterSizeHint() const {
  QFontMetrics metrics(mFont);
  QSize result(
      metrics.boundingRect(0, 0, 0, 0, Qt::TextDontClip, mText[0]).size());
  result.setWidth(QWIDGETSIZE_MAX);
  result.rheight() += mMargins.top() + mMargins.bottom() + 8;
  return result;
}

/* inherits documentation from base class */
void BaseChartTextElement::selectEvent(QMouseEvent* event, bool additive,
                                       const QVariant& details,
                                       bool* selectionStateChanged) {
  Q_UNUSED(event)
  Q_UNUSED(details)
  if (mSelectable) {
    bool selBefore = mSelected;
    setSelected(additive ? !mSelected : true);
    if (selectionStateChanged) *selectionStateChanged = mSelected != selBefore;
  }
}

/* inherits documentation from base class */
void BaseChartTextElement::deselectEvent(bool* selectionStateChanged) {
  if (mSelectable) {
    bool selBefore = mSelected;
    setSelected(false);
    if (selectionStateChanged) *selectionStateChanged = mSelected != selBefore;
  }
}

/*!
  Returns 0.99*selectionTolerance (see \ref
  BaseChartCustomPlot::setSelectionTolerance) when \a pos is within the bounding
  box of the text element's text. Note that this bounding box is updated in the
  draw call.

  If \a pos is outside the text's bounding box or if \a onlySelectable is true
  and this text element is not selectable (\ref setSelectable), returns -1.

  \seebaseclassmethod
*/
double BaseChartTextElement::selectTest(const QPointF& pos, bool onlySelectable,
                                        QVariant* details) const {
  Q_UNUSED(details)
  if (onlySelectable && !mSelectable) return -1;

  if (mTextBoundingRect.contains(pos.toPoint()))
    return mParentPlot->selectionTolerance() * 0.99;
  else
    return -1;
}

/*!
  Accepts the mouse event in order to emit the according click signal in the
  \ref mouseReleaseEvent.

  \seebaseclassmethod
*/
void BaseChartTextElement::mousePressEvent(QMouseEvent* event,
                                           const QVariant& details) {
  Q_UNUSED(details)
  event->accept();
}

/*!
  Emits the \ref clicked signal if the cursor hasn't moved by more than a few
  pixels since the \ref mousePressEvent.

  \seebaseclassmethod
*/
void BaseChartTextElement::mouseReleaseEvent(QMouseEvent* event,
                                             const QPointF& startPos) {
  if ((QPointF(event->pos()) - startPos).manhattanLength() <= 3)
    emit clicked(event);
}

/*!
  Emits the \ref doubleClicked signal.

  \seebaseclassmethod
*/
void BaseChartTextElement::mouseDoubleClickEvent(QMouseEvent* event,
                                                 const QVariant& details) {
  Q_UNUSED(details)
  emit doubleClicked(event);
}

/*! \internal

  Returns the main font to be used. This is mSelectedFont if \ref setSelected is
  set to <tt>true</tt>, else mFont is returned.
*/
QFont BaseChartTextElement::mainFont() const {
  return mSelected ? mSelectedFont : mFont;
}

/*! \internal

  Returns the main color to be used. This is mSelectedTextColor if \ref
  setSelected is set to <tt>true</tt>, else mTextColor is returned.
*/
QColor BaseChartTextElement::mainTextColor() const {
  return mSelected ? mSelectedTextColor : mTextColor;
}

void BaseChartTextElement::setTextOffset(int offset) { mOffset = offset; }

void BaseChartTextElement::setCustomDraw(
    BaseChartCustomTextElement* customTextElement) {
  mCustomTextElement = customTextElement;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////// BaseChartDragBarElement
////////////////////////////////////////////////////////////////////////////////////////////////////

/*! \class BaseChartDragBarElement
  \brief A layout element displaying a text

  The text may be specified with \ref setText, the formatting can be controlled
  with \ref setFont, \ref setTextColor, and \ref setTextFlags.

  A text element can be added as follows:
  \snippet documentation/doc-code-snippets/mainwindow.cpp
  qcptextelement-creation
*/

/* start documentation of signals */

/*! \fn void BaseChartDragBarElement::selectionChanged(bool selected)

  This signal is emitted when the selection state has changed to \a selected,
  either by user interaction or by a direct call to \ref setSelected.

  \see setSelected, setSelectable
*/

/*! \fn void BaseChartDragBarElement::clicked(QMouseEvent *event)

  This signal is emitted when the text element is clicked.

  \see doubleClicked, selectTest
*/

/*! \fn void BaseChartDragBarElement::doubleClicked(QMouseEvent *event)

  This signal is emitted when the text element is double clicked.

  \see clicked, selectTest
*/

/* end documentation of signals */

/*! \overload

  Creates a new BaseChartDragBarElement instance and sets default values. The
  initial text is empty (\ref setText).
*/

#define DRAGBAR_WIDTH 18
#define MARGIN_WIDTH 2

BaseChartDragBarElement::BaseChartDragBarElement(
    BaseChartCustomPlot* parentPlot)
    : BaseChartLayoutElement(parentPlot),
      mBarColor(Qt::gray),
      mBarHeight(6),
      mBarPos1(MARGIN_WIDTH),
      mBarPos2(0),
      mPos12(0),
      mDragging1(false),
      mDragging2(false),
      mDragging12(false),
      mSelectable(false),
      mSelected(false),
      mEnable(true) {
  mOrgRect.setRect(0, 0, 0, 0);
  setMargins(QMargins(MARGIN_WIDTH, 6, MARGIN_WIDTH, 0));
}

/*!
  Sets the \a color of the text.

  \see setFont, setSelectedBarColor
*/
void BaseChartDragBarElement::setBarColor(const QColor& color) {
  mBarColor = color;
}

void BaseChartDragBarElement::setBarHeight(int height) { mBarHeight = height; }

/*!
  Sets whether the user may select this text element.

  Note that even when \a selectable is set to <tt>false</tt>, the selection
  state may be changed programmatically via \ref setSelected.
*/
void BaseChartDragBarElement::setSelectable(bool selectable) {
  if (mSelectable != selectable) {
    mSelectable = selectable;
    emit selectableChanged(mSelectable);
  }
}

/*!
  Sets the selection state of this text element to \a selected. If the selection
  has changed, \ref selectionChanged is emitted.

  Note that this function can change the selection state independently of the
  current \ref setSelectable state.
*/
void BaseChartDragBarElement::setSelected(bool selected) {
  if (mSelected != selected) {
    mSelected = selected;
    emit selectionChanged(mSelected);
  }
}

void BaseChartDragBarElement::setEnable(bool enable) { mEnable = enable; }

void BaseChartDragBarElement::setPos(int pos1, int pos2) {
  mBarPos1 = pos1 + mRect.left();
  mBarPos2 = pos2 + mRect.left();

  if (mBarPos1 < mRect.left()) {
    mBarPos1 = mRect.left();
  }
  if (mBarPos2 > mRect.right() - DRAGBAR_WIDTH) {
    mBarPos2 = mRect.right() - DRAGBAR_WIDTH;
  }

  mParentPlot->replot(BaseChartCustomPlot::rpImmediateRefresh);
}

/* inherits documentation from base class */
void BaseChartDragBarElement::applyDefaultAntialiasingHint(
    BaseChartPainter* painter) const {
  applyAntialiasingHint(painter, mAntialiased, aeOther);
}

/* inherits documentation from base class */
void BaseChartDragBarElement::draw(BaseChartPainter* painter) {
  drawBk(painter);
  drawBar(painter);
}

void BaseChartDragBarElement::drawBk(BaseChartPainter* painter) {
  if (!mEnable) {
    painter->fillRect(mRect, QColor(18, 26, 25));
  } else {
    painter->fillRect(mRect, QColor(23, 36, 34));

    if (mOrgRect.width() == 0) {
      mOrgRect = mRect;
    } else if (mOrgRect.width() != mRect.width()) {
      double dRatio = (double)mRect.width() / (double)mOrgRect.width();

      if (mBarPos1 != mOrgRect.left()) {
        mBarPos1 = mOrgRect.left() + (mBarPos1 - mOrgRect.left()) * dRatio;
      }

      if (mBarPos2 != 0) {
        if (mBarPos2 < mOrgRect.right() - DRAGBAR_WIDTH) {
          mBarPos2 = mOrgRect.left() + (mBarPos2 - mOrgRect.left()) * dRatio;
        } else {
          mBarPos2 = mRect.right() - DRAGBAR_WIDTH;
        }
      }

      mOrgRect = mRect;
    }

    if (mBarPos2 <= 0) {
      mBarPos2 = mRect.right() - DRAGBAR_WIDTH;
    }

    QColor clrDistance;
    if (mBarPos1 <= mRect.left() &&
            mBarPos2 >= (mRect.right() - DRAGBAR_WIDTH) ||
        mDragging1 || mDragging2) {
      clrDistance = QColor(38, 55, 53);
    } else {
      clrDistance = QColor(65, 50, 23);
    }

    QRect rcDistance = mRect;
    rcDistance.setTop(rcDistance.top() + 1);
    rcDistance.setBottom(rcDistance.bottom() - 2);
    rcDistance.setLeft(mBarPos1 + DRAGBAR_WIDTH);
    rcDistance.setRight(mBarPos2);

    painter->fillRect(rcDistance, clrDistance);

    if (mBarPos1 > mRect.left()) {
      QRect rcBlank = rcDistance;
      rcBlank.setLeft(mRect.left());
      rcBlank.setRight(mBarPos1);
      painter->fillRect(rcBlank, QColor(18, 26, 25));
    }
    if (mBarPos2 < (mRect.right() - DRAGBAR_WIDTH)) {
      QRect rcBlank = rcDistance;
      rcBlank.setLeft(mBarPos2 + DRAGBAR_WIDTH);
      rcBlank.setRight(mRect.right());
      painter->fillRect(rcBlank, QColor(18, 26, 25));
    }

    if (!mDragging12) {
      mDistanceRect = rcDistance;
    }
  }
}

void BaseChartDragBarElement::drawBar(BaseChartPainter* painter) {
  int pos = mBarPos1;
  if (pos < 0) {
    pos = mRect.left();
  }

  mBarRect1 = mRect;
  mBarRect1.setLeft(pos + 1);
  mBarRect1.setRight(mBarRect1.left() + (DRAGBAR_WIDTH - 2));
  mBarRect1.setBottom(mBarRect1.bottom() - 2);

  QPen oldPen = painter->pen();
  QBrush oldBrush = painter->brush();

  if (mEnable) {
    painter->setPen(QColor(35, 66, 74));
    painter->setBrush(QColor(35, 66, 74));
  } else {
    painter->setPen(QColor(74, 77, 76));
    painter->setBrush(QColor(74, 77, 76));
  }

  painter->drawRoundedRect(mBarRect1, 2, 2);
  painter->setPen(oldPen);
  painter->setBrush(oldBrush);

  pos = mBarPos2;
  if (mBarPos2 <= 0) {
    pos = mRect.right() - (DRAGBAR_WIDTH - 2);
  }

  mBarRect2 = mRect;
  mBarRect2.setLeft(pos + 1);
  mBarRect2.setRight(mBarRect2.left() + (DRAGBAR_WIDTH - 2));
  mBarRect2.setBottom(mBarRect2.bottom() - 2);

  oldPen = painter->pen();
  oldBrush = painter->brush();

  if (mEnable) {
    painter->setPen(QColor(35, 66, 74));
    painter->setBrush(QColor(35, 66, 74));
  } else {
    painter->setPen(QColor(74, 77, 76));
    painter->setBrush(QColor(74, 77, 76));
  }

  painter->drawRoundedRect(mBarRect2, 2, 2);
  painter->setPen(oldPen);
  painter->setBrush(oldBrush);

  painter->setPen(QColor(220, 210, 180));
  painter->drawLine(QLineF(mBarRect1.left() + 8, mBarRect1.top() + 2,
                           mBarRect1.left() + 8, mBarRect1.bottom() - 1));
  painter->drawLine(QLineF(mBarRect1.left() + 10, mBarRect1.top() + 2,
                           mBarRect1.left() + 10, mBarRect1.bottom() - 1));
  painter->drawLine(QLineF(mBarRect2.left() + 8, mBarRect2.top() + 2,
                           mBarRect2.left() + 8, mBarRect2.bottom() - 1));
  painter->drawLine(QLineF(mBarRect2.left() + 10, mBarRect2.top() + 2,
                           mBarRect2.left() + 10, mBarRect2.bottom() - 1));
}

/* inherits documentation from base class */
QSize BaseChartDragBarElement::minimumOuterSizeHint() const {
  QSize result;
  result.rwidth() += mMargins.left() + mMargins.right();
  result.rheight() += mBarHeight + mMargins.top() + mMargins.bottom() + 4;
  return result;
}

/* inherits documentation from base class */
QSize BaseChartDragBarElement::maximumOuterSizeHint() const {
  QSize result;
  result.setWidth(QWIDGETSIZE_MAX);
  result.rheight() += mBarHeight + mMargins.top() + mMargins.bottom() + 4;
  return result;
}

/* inherits documentation from base class */
void BaseChartDragBarElement::selectEvent(QMouseEvent* event, bool additive,
                                          const QVariant& details,
                                          bool* selectionStateChanged) {
  Q_UNUSED(event)
  Q_UNUSED(details)
  if (mSelectable) {
    bool selBefore = mSelected;
    setSelected(additive ? !mSelected : true);
    if (selectionStateChanged) *selectionStateChanged = mSelected != selBefore;
  }
}

/* inherits documentation from base class */
void BaseChartDragBarElement::deselectEvent(bool* selectionStateChanged) {
  if (mSelectable) {
    bool selBefore = mSelected;
    setSelected(false);
    if (selectionStateChanged) *selectionStateChanged = mSelected != selBefore;
  }
}

/*!
  Returns 0.99*selectionTolerance (see \ref
  BaseChartCustomPlot::setSelectionTolerance) when \a pos is within the bounding
  box of the text element's text. Note that this bounding box is updated in the
  draw call.

  If \a pos is outside the text's bounding box or if \a onlySelectable is true
  and this text element is not selectable (\ref setSelectable), returns -1.

  \seebaseclassmethod
*/
double BaseChartDragBarElement::selectTest(const QPointF& pos,
                                           bool onlySelectable,
                                           QVariant* details) const {
  Q_UNUSED(details)
  if (onlySelectable && !mSelectable) return -1;

  if (mRect.contains(pos.toPoint()))
    return mParentPlot->selectionTolerance() * 0.99;
  else
    return -1;
}

/*!
  Accepts the mouse event in order to emit the according click signal in the
  \ref mouseReleaseEvent.

  \seebaseclassmethod
*/
void BaseChartDragBarElement::mousePressEvent(QMouseEvent* event,
                                              const QVariant& details) {
  Q_UNUSED(details)

  if (!mEnable) {
    return;
  }
  if (event->buttons() & Qt::LeftButton) {
    if (mBarRect1.contains(event->pos())) {
      mDragging1 = true;
      mParentPlot->setCursor(Qt::SizeHorCursor);
    } else if (mBarRect2.contains(event->pos())) {
      mDragging2 = true;
      mParentPlot->setCursor(Qt::SizeHorCursor);
    } else if (mDistanceRect.contains(event->pos())) {
      mDragging12 = true;
      mPos12 = event->pos().x();
    }
  }
}

/*! \internal

  This mouse event reimplementation provides the functionality to let the user
  drag individual axes exclusively, by startig the drag on top of the axis.

  \seebaseclassmethod

  \note The dragging of possibly multiple axes at once by starting the drag
  anywhere in the axis rect is handled by the axis rect's mouse event, e.g. \ref
  BaseChartAxisRect::mousePressEvent.

  \see BaseChartAxis::mousePressEvent
*/
void BaseChartDragBarElement::mouseMoveEvent(QMouseEvent* event,
                                             const QPointF& startPos) {
  Q_UNUSED(startPos)

  if (!mEnable || !mRect.width()) {
    return;
  }

  if (mDragging1) {
    mBarPos1 = event->pos().x() - DRAGBAR_WIDTH / 2;
    if (mBarPos1 < 0) {
      mBarPos1 = mRect.left();
    }
    if (mBarPos2 > 0) {
      if (mBarPos1 + DRAGBAR_WIDTH >= mBarPos2) {
        mBarPos1 = mBarPos2 - DRAGBAR_WIDTH;
      }
      if (mBarPos1 >= 0 && mBarPos1 + DRAGBAR_WIDTH <= mBarPos2) {
        mParentPlot->replot(BaseChartCustomPlot::rpImmediateRefresh);
      }
    } else {
      if (mBarPos1 + DRAGBAR_WIDTH >= mRect.right() - DRAGBAR_WIDTH) {
        mBarPos1 = mRect.right() - DRAGBAR_WIDTH - DRAGBAR_WIDTH;
      }
      if (mBarPos1 >= 0 &&
          mBarPos1 + DRAGBAR_WIDTH <= mRect.right() - DRAGBAR_WIDTH) {
        mParentPlot->replot(BaseChartCustomPlot::rpImmediateRefresh);
      }
    }

    emit leftDrag((double)mBarPos1 / mRect.width());
  } else if (mDragging2) {
    mBarPos2 = event->pos().x() - DRAGBAR_WIDTH / 2;
    if (mBarPos2 + DRAGBAR_WIDTH > mRect.right()) {
      mBarPos2 = mRect.right() - DRAGBAR_WIDTH;
    }
    if (mBarPos1 + DRAGBAR_WIDTH >= mBarPos2) {
      mBarPos2 = mBarPos1 + DRAGBAR_WIDTH;
    }
    if (mBarPos1 + DRAGBAR_WIDTH <= mBarPos2 &&
        mBarPos2 + DRAGBAR_WIDTH <= mRect.right()) {
      mParentPlot->replot(BaseChartCustomPlot::rpImmediateRefresh);
    }

    emit rightDrag((double)(mBarPos2 + DRAGBAR_WIDTH) / mRect.width());
  } else if (mDragging12) {
    if (mBarPos1 <= mRect.left() && mBarPos2 + DRAGBAR_WIDTH >= mRect.right()) {
      return;
    }

    int nDistance = event->pos().x() - mPos12;
    mPos12 = event->pos().x();
    mBarPos1 += nDistance;
    mBarPos2 += nDistance;
    if (mBarPos1 < 0) {
      mBarPos1 = mRect.left();
      mBarPos2 = mBarPos1 + DRAGBAR_WIDTH + mDistanceRect.width();
    } else if (mBarPos2 + DRAGBAR_WIDTH > mRect.right()) {
      mBarPos2 = mRect.right() - DRAGBAR_WIDTH;
      mBarPos1 = mBarPos2 - DRAGBAR_WIDTH - mDistanceRect.width();
    } else {
      mBarPos2 = mBarPos1 + DRAGBAR_WIDTH + mDistanceRect.width();
    }

    mParentPlot->replot(BaseChartCustomPlot::rpImmediateRefresh);

    emit centralDrag((double)mBarPos1 / mRect.width(),
                     (double)(mBarPos2 + DRAGBAR_WIDTH) / mRect.width());
  }
}

/*!
  Emits the \ref clicked signal if the cursor hasn't moved by more than a few
  pixels since the \ref mousePressEvent.

  \seebaseclassmethod
*/
void BaseChartDragBarElement::mouseReleaseEvent(QMouseEvent* event,
                                                const QPointF& startPos) {
  if (!mEnable) {
    return;
  }

  mDragging1 = false;
  mDragging2 = false;
  mDragging12 = false;
  mParentPlot->setCursor(Qt::ArrowCursor);
  mParentPlot->replot(BaseChartCustomPlot::rpImmediateRefresh);
}

/*!
  Emits the \ref doubleClicked signal.

  \seebaseclassmethod
*/
void BaseChartDragBarElement::mouseDoubleClickEvent(QMouseEvent* event,
                                                    const QVariant& details) {
  Q_UNUSED(details)

  if (!mEnable) {
    return;
  }

  emit doubleClicked(event);
}